/*
 * Copyright (c) 2018-present, lmyooyo@gmail.com.
 *
 * This source code is licensed under the GPL license found in the
 * LICENSE file in the root directory of this source tree.
 */
package com.zhg.videorecord.collect

import android.hardware.Camera
import android.os.Build
import android.view.SurfaceHolder
import android.view.SurfaceView
import androidx.annotation.RequiresApi
import com.lmy.codec.pipeline.impl.GLEventPipeline
import com.zhg.videorecord.entity.CodecContext
import com.zhg.videorecord.helper.TLog

/**
 * desc: 相机预览
 * author: ZHG
 * date: 2020/3/19
 */
@RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
class CameraSurfaceWrapper(private var context: CodecContext,
                           private var onPreviewCallback: Camera.PreviewCallback) {
    companion object {
        private val PREPARE = 0x1
        fun open(param: CodecContext, onPreviewCallback: Camera.PreviewCallback)
                : CameraSurfaceWrapper {
            return CameraSurfaceWrapper(param, onPreviewCallback)
        }
    }

    private var mCamera: Camera? = null
    private var mCameras = 0
    private var mCameraIndex: CameraWrapper.CameraIndex? = null
    private var surfaceView:SurfaceView?=null;
    private var surfaceHolder:SurfaceHolder?=null;

    private val useSameBuffer=false
    init {
        mCameras = CameraHelper.getNumberOfCameras()
        openCamera(context.cameraIndex)
    }

    fun post(runnable: Runnable): CameraSurfaceWrapper {
        GLEventPipeline.INSTANCE.queueEvent(runnable)
        return this
    }

    @RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    fun switchCamera(index: CameraWrapper.CameraIndex) {
        openCamera(index)
    }

    @RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    private fun openCamera(index: CameraWrapper.CameraIndex) {
        val tmp = if (index == CameraWrapper.CameraIndex.FRONT && mCameras < 2) {//如果没有前置摄像头，则强制使用后置摄像头
            CameraWrapper.CameraIndex.BACK
        } else {
            index
        }
        if (null != mCameraIndex && mCameraIndex == tmp) //如果已经打开过摄像头，并且当前已经是index，则不做改变
            return
        mCameraIndex = tmp
        context.cameraIndex = tmp

    }
    fun start(holder: SurfaceHolder?){
        this.surfaceHolder=holder
        GLEventPipeline.INSTANCE.queueEvent(Runnable {
            stopPreview()
            prepare()
            startPreview()
        })
    }



    private fun getCameraIndex(): Int {
        if (context.cameraIndex == CameraWrapper.CameraIndex.FRONT)
            return Camera.CameraInfo.CAMERA_FACING_FRONT
        return Camera.CameraInfo.CAMERA_FACING_BACK
    }

    private fun prepare() {
        if (0 == mCameras) {
            TLog.i("Unavailable camera")
            return
        }

        val time = System.currentTimeMillis()
        mCamera = openCamera(getCameraIndex())
        TLog.i("open time: ${System.currentTimeMillis() - time}")
        if (null == mCamera) {
            TLog.i("mCamera is null!")
            return
        }
        val cameraParam = mCamera!!.parameters
        CameraHelper.setPreviewSize(cameraParam, context)
        CameraHelper.setColorFormat(cameraParam, context)
        CameraHelper.setFocusMode(cameraParam, context)
        CameraHelper.setFps(cameraParam, context)
        //自动曝光锁定
        CameraHelper.setAutoExposureLock(cameraParam, false)
        CameraHelper.setSceneMode(cameraParam, Camera.Parameters.SCENE_MODE_AUTO)
        CameraHelper.setFlashMode(cameraParam, Camera.Parameters.FLASH_MODE_OFF)
        CameraHelper.setAntibanding(cameraParam, Camera.Parameters.ANTIBANDING_AUTO)
        CameraHelper.setVideoStabilization(cameraParam, true)
        CameraHelper.setPreviewFormat(cameraParam);
        //曝光补偿
       // CameraHelper.setExposureCompensation(cameraParam,12)
        //CameraHelper.setMeteringAreas(cameraParam,mCamera)
        CameraHelper.setWhiteBalance(cameraParam,context)
        val fps = IntArray(2)
        cameraParam.getPreviewFpsRange(fps)
        TLog.i("Config: Size(${context.cameraSize.width}x${context.cameraSize.height})\n" +
                "Format(${cameraParam.previewFormat})\n" +
                "FocusMode(${cameraParam.focusMode})\n" +
                "Fps(${fps[0]}-${fps[1]})\n" +
                "AutoExposureLock(${cameraParam.autoExposureLock})\n" +
                "SceneMode(${cameraParam.sceneMode})\n" +
                "FlashMode(${cameraParam.flashMode})\n" +
                "Antibanding(${cameraParam.antibanding})\n" +
                "VideoStabilization(${cameraParam.videoStabilization})")
        try {
            mCamera!!.parameters = cameraParam
            TLog.i("Camera config")
        } catch (e: Exception) {
            mCamera?.release()
            TLog.e("Camera $mCameraIndex open failed. Please check parameters")
        }
    }

    private fun openCamera(index: Int): Camera? {
        return try {
            val camera = Camera.open(index)
            camera.setDisplayOrientation(context.orientation)
            camera
        } catch (e: SecurityException) {
            TLog.e("Camera $index open failed, No permission")
            e.printStackTrace()
            null
        } catch (e: Exception) {
            TLog.e("Camera $index open failed")
            e.printStackTrace()
            null
        }
    }

    @RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    fun release() {
        GLEventPipeline.INSTANCE.queueEvent(Runnable {
            stopPreview()
        })
    }

    private fun startPreview() {
        if (null == mCamera) {
            TLog.e("Start preview failed, mCamera is null")
            return
        }
        try {
            mCamera!!.setPreviewDisplay(surfaceHolder)
            if (useSameBuffer){
                setPreviewCallbackWithBuffer()
            }else{
               setPreviewCallback()
            }
            mCamera!!.startPreview()
        } catch (e: Exception) {
            release()
            TLog.e("Start preview failed")
            e.printStackTrace()
        }
    }
    private fun setPreviewCallback(){
        //每次新建缓冲区，容易造成内存抖动频繁gc
        mCamera!!.setPreviewCallback { data, camera ->
            onPreviewCallback.onPreviewFrame(data!!,camera!!) }
    }
    /**
     * desc:
     * author: ZHG
     * date: 2020/4/19
     */
    private fun setPreviewCallbackWithBuffer(){
        //手动分配缓冲区
         //一帧预览图大小，width * height *ImageFormat.getBitsPerPixel(ImageFormat.NV21) / 8，
        //即w*h*1.5，nv21 一个像素需要12bit/8=1.5byte存储
        var buffSize= context.cameraSize.width * context.cameraSize.height * 3 / 2
        //添加用于相机进行处理的 byte[] buffer 对象可以多设置几个，触发多次onPreviewFrame
        mCamera!!.addCallbackBuffer(ByteArray(buffSize))
        //mCamera!!.addCallbackBuffer(ByteArray(buffSize))
        //启动预览，每产生一帧都会回调onPreviewFrame()，但每一帧的数据都是一块新的内存区域会造成频繁的 GC
        //内每一帧的 data 就会复用同一块缓冲区域，data 对象没有改变，但是 data 数据的内容改变了，
        // 并且该回调不会返回每一帧的数据，而是在重新调用 addCallbackBuffer 之后才会继续回调
        mCamera!!.setPreviewCallbackWithBuffer(object :Camera.PreviewCallback{
            override fun onPreviewFrame(data: ByteArray?, camera: Camera?) {
                onPreviewCallback.onPreviewFrame(data!!,camera!!)
                //完成对其中数据的处理后，添加回缓冲区
                mCamera!!.addCallbackBuffer(data)
            }
        })
    }


    private fun stopPreview() {
        if (null == mCamera) return
        try {
            mCamera!!.setPreviewCallback(null)
            mCamera!!.stopPreview()
            mCamera!!.release()
            mCamera = null
        } catch (e: Exception) {
            TLog.e("Stop preview failed")
            e.printStackTrace()
        }
    }
    private fun startFaceDetection() {
        mCamera!!.setFaceDetectionListener(object :Camera.FaceDetectionListener{
            override fun onFaceDetection(faces: Array<out Camera.Face>?, p1: Camera?) {
            }

        })
        val params = mCamera!!.getParameters()

        // start face detection only *after* preview has started
        if (params.maxNumDetectedFaces > 0) {
            // camera supports face detection, so can start it:
            mCamera!!.startFaceDetection()
        }
    }


}